package com.pedro.encoder.input.gl.render.filters;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.Matrix;
import android.os.Build;
import android.os.SystemClock;
import android.util.Log;

import androidx.annotation.RequiresApi;

import com.pedro.encoder.R;
import com.pedro.encoder.utils.gl.GlUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Random;

/**
 * 放大镜
 */
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public class MagnifierFilter extends BaseFilterRender{

    private static final String TAG = "MagnifierFilter";

    private static final String MAGNIFIER_FRAGMENT_SHADER = "precision highp float;\n" +
            "precision highp int;\n" +
            "\n" +
            "// NOTE\n" +
            "// https://godotshaders.com/shader/magnifier-shader/\n" +
            "\n" +
            "uniform sampler2D sTexture;\n" +
            "\n" +
            "// Screen resolution.\n" +
            "uniform vec2 screen_res;\n" +
            "\n" +
            "// Target position as center of magnifilter.\n" +
            "uniform vec2 center_pos;\n" +
            "\n" +
            "// Variable to describe how magnify. [0, 1)\n" +
            "uniform float magnification;\n" +
            "\n" +
            "// Radius to adopt magnification.\n" +
            "uniform float radius;\n" +
            "\n" +
            "// Line width of magnifier circle.\n" +
            "uniform float circle_line_width;\n" +
            "\n" +
            "// Line color of magnifier circle.\n" +
            "uniform vec3 circle_line_color;\n" +
            "\n" +
            "// In OpenGL ES 2.0, use 'varying' instead of 'in'\n" +
            "varying vec2 vTextureCoord;\n" +
            "\n" +
            "// output colour for the fragment\n" +
            "// OpenGL ES 2.0 doesn't have explicit 'out' variables\n" +
            "// The output color is written to 'gl_FragColor'\n" +
            "\n" +
            "void main()\n" +
            "{\n"  +
            "    // NOTE:\n" +
            "    // e.g. center_pos is center of screen.\n" +
            "    // (0,0)                  (1,0)\n" +
            "    //   +---------------------+\n" +
            "    //   |       (0.5,0.5)     |\n" +
            "    //   |          +     x    * (1,0.5)\n" +
            "    //   |           (0.75,0.5)|\n" +
            "    //   +---------------------+\n" +
            "    // (0,1)                  (1,1)\n" +
            "    vec2 center_uv = center_pos / screen_res;\n" +
            "\n" +
            "    // Compute proportional vTextureCoord to magnify.\n" +
            "    vec2 magnifiled_uv = mix(vTextureCoord, center_uv, magnification);\n" +
            "\n" +
            "    vec2 frag_coord = gl_FragCoord.xy;\n" +
            "    frag_coord.y = screen_res.y - frag_coord.y;\n" +
            "\n" +
            "    float d = length(frag_coord - center_pos);\n" +
            "    if (d > radius)\n" +
            "    {\n" +
            "        magnifiled_uv = vTextureCoord;\n" +
            "    }\n" +
            "\n" +
            "    if (radius < d && d <= (radius + circle_line_width)) {\n" +
            "        gl_FragColor.rgb = circle_line_color;\n" +
            "    }\n" +
            "    else {\n" +
            "        vec4 color = texture2D(sTexture, magnifiled_uv);\n" +
            "        gl_FragColor.rgb = color.rgb;\n" +
            "    }\n" +
            "\n" +
            "    gl_FragColor.a = 1.0;\n" +
            "}";


    private final float[] squareVertexDataFilter = {
            // X, Y, Z, U, V
            -1f, -1f, 0f, 0f, 0f, //bottom left
            1f, -1f, 0f, 1f, 0f, //bottom right
            -1f, 1f, 0f, 0f, 1f, //top left
            1f, 1f, 0f, 1f, 1f, //top right
    };
    private int program = -1;
    private int aPositionHandle = -1;
    private int aTextureHandle = -1;
    private int uMVPMatrixHandle = -1;
    private int uSTMatrixHandle = -1;
    private int uSamplerHandle = -1;
    private int uScreenRes = -1;
    private int uCenterPos = -1;
    private int uMagnification = -1;
    private int uRadius = -1;
    private int uCircleLineWidth = -1;
    private int uCircleLineColor = -1;



    //parm
    private float centorX=0;
    private float centorY=0;
    public float magnification=0.3f;
    public float radius=180f;
    private float uircleLineWidth=0f;

    //是否水平方向移动
    public boolean left2right=false;
    public boolean right2left=false;
    //水平方向移动完成一次的时长，多少秒
    public float period = 5f;

    private float speedX = 0.1f;
    private  int interval=3000;//时间间隔，每多少毫秒出发一次特效，默认200ms
    private long startTime=0;

    private float speedY = 0.01f;

    boolean randomMove = true;

    float[] numbers = {0.05f, 0.1f, 0.5f, 0.7f, 1.0f, 1.1f};

    float a = 1.0f;

    public MagnifierFilter(){
        squareVertex = ByteBuffer.allocateDirect(squareVertexDataFilter.length * FLOAT_SIZE_BYTES)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        squareVertex.put(squareVertexDataFilter).position(0);
        Matrix.setIdentityM(MVPMatrix, 0);
        Matrix.setIdentityM(STMatrix, 0);
    }
    @Override
    protected void initGlFilter(Context context) {
        String vertexShader = GlUtil.getStringFromRaw(context, R.raw.simple_vertex);
        String fragmentShader =MAGNIFIER_FRAGMENT_SHADER;// GlUtil.getStringFromRaw(context, R.raw.magnifier_fs);
        program = GlUtil.createProgram(vertexShader, fragmentShader);
        aPositionHandle = GLES20.glGetAttribLocation(program, "aPosition");
        aTextureHandle = GLES20.glGetAttribLocation(program, "aTextureCoord");
        uMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
        uSTMatrixHandle = GLES20.glGetUniformLocation(program, "uSTMatrix");

        uSamplerHandle = GLES20.glGetUniformLocation(program, "sTexture");

        uScreenRes = GLES20.glGetUniformLocation(program, "screen_res");
        uCenterPos = GLES20.glGetUniformLocation(program, "center_pos");
        uMagnification = GLES20.glGetUniformLocation(program, "magnification");
        uRadius = GLES20.glGetUniformLocation(program, "radius");
        uCircleLineWidth = GLES20.glGetUniformLocation(program, "circle_line_width");
        uCircleLineColor = GLES20.glGetUniformLocation(program, "circle_line_color");
        startTime=SystemClock.elapsedRealtime();
    }


    @Override
    protected void drawFilter() {
        GLES20.glUseProgram(program);

        squareVertex.position(SQUARE_VERTEX_DATA_POS_OFFSET);
        GLES20.glVertexAttribPointer(aPositionHandle, 3, GLES20.GL_FLOAT, false,
                SQUARE_VERTEX_DATA_STRIDE_BYTES, squareVertex);
        GLES20.glEnableVertexAttribArray(aPositionHandle);

        squareVertex.position(SQUARE_VERTEX_DATA_UV_OFFSET);
        GLES20.glVertexAttribPointer(aTextureHandle, 2, GLES20.GL_FLOAT, false,
                SQUARE_VERTEX_DATA_STRIDE_BYTES, squareVertex);
        GLES20.glEnableVertexAttribArray(aTextureHandle);

        GLES20.glUniformMatrix4fv(uMVPMatrixHandle, 1, false, MVPMatrix, 0);
        GLES20.glUniformMatrix4fv(uSTMatrixHandle, 1, false, STMatrix, 0);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, previousTexId);
        GLES20.glUniform1i(uSamplerHandle, 4);

        if (randomMove) {
            if (SystemClock.elapsedRealtime() - startTime > interval){
                Random random = new Random();
                int randomIndex = random.nextInt(numbers.length);
                a = numbers[randomIndex];
                startTime=SystemClock.elapsedRealtime();
            }
        }

        long currentTime = System.currentTimeMillis();
        double angle = currentTime / 1000.0 * 2.0 * Math.PI * speedX;
        double angle2 = currentTime / 1000.0 * 2.0 * Math.PI * (speedX * a);
        // 计算正弦函数
        double sineValueX = Math.sin(angle);
        double sineValueY = Math.sin(angle2);

        Log.d(TAG, "currentTime: " + speedX);
        Log.d(TAG, "sineValue: " + speedX / 10.00f);

        float mX = (float) (0.5f + (sineValueX * 0.5f));
        float mY = (float) (0.5f + (sineValueY * 0.5f));

        //
//        if (centorX==0&&centorY==0){
            centorX=getWidth()*mX;
            centorY=getHeight()*mY;
//        }

        GLES20.glUniform2f(uScreenRes, getWidth(), getHeight());
        GLES20.glUniform2f(uCenterPos, centorX,centorY);
        GLES20.glUniform1f(uMagnification, magnification);
        GLES20.glUniform1f(uRadius, radius);
        GLES20.glUniform1f(uCircleLineWidth, uircleLineWidth);
//        GLES20.glUniform3f(uCircleLineColor, 255,255,0);//yellow
        GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, previousTexId);

//        if (left2right||right2left){
//            // 获取当前时间
//            long currentTime = System.currentTimeMillis();
//            // 周期
//            float normalizedTime = (currentTime % (long)(period*1000)) / 1000.0f;  // [0, period] 归一化
//            // 将归一化的时间转换为中心的 x 坐标
//            float tornadoCenterX=0;
//            if (left2right){
//                tornadoCenterX= normalizedTime / period;
//            }else{
//                tornadoCenterX = 1.0f - (normalizedTime / period);
//            }
//
//            GLES20.glUniform2f(uCenterPos, tornadoCenterX*getWidth(), centorY);
//
//
//        }
        Log.d("TAG", "放大镜X: " + centorX);
        Log.d("TAG", "放大镜Y: " + centorY);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, previousTexId);

    }

    @Override
    public void release() {
        GLES20.glDeleteProgram(program);
    }
    public void setTouchXY(int x,int y){
        this.centorX=x;
        this.centorX=y;
    }

    /**
     * 放大率 0-100
     * @param magnification
     */
    public void setMagnification(int magnification){
        this.magnification= (float) magnification /100;
    }

    /**
     * 放大镜半径，不要超过屏幕的一半
     * @param radius
     */
    public void setRadius(int radius){
       this.radius=radius;
    }

    public void setSpeedX(float speedX) {
        this.speedX = speedX;
    }
}
